#include "MsgParser.h"
#include "mdefines.h"
#include <QDebug>
#include <QDateTime>
#include "MsgStruct.h"
#include "sixbitstring.h"
#include "mylogger.h"
#include <qexception.h>
#include "commonutil.h"
#include "LonLatUtil.h"
#include "gtime.h"
#include "deviceType.h"
#include <QTime>
#include <QTimeZone>
#include "datapostback.h"
using namespace ns_yht;

Q_GLOBAL_STATIC(MsgParser, g_msgParser)

MsgParser::MsgParser() : SIX_BIT_ASCII("@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_ !\"#$%&'()*+,-./0123456789:;<=>?"),
                         SIX_BIT_ARMOR("0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVW`abcdefghijklmnopqrstuvw")
{
    for (int i = DeviceType::Ais; i < DeviceType::Other; i++)
    {
        m_deviceUpdateTime[i] = 0; // GTime::getUtcTime_s();
    }
    m_AISLastTime = QDateTime::currentDateTime().toSecsSinceEpoch();
}

MsgParser::~MsgParser()
{
}

MsgParser *MsgParser::instance()
{
    return g_msgParser();
}

void MsgParser::setPostback(bool postBack)
{
    m_postback = postBack;
    if (m_postback)
    {
        connect(this, &MsgParser::postbackData, DATAPOSTBACK, &DataPostback::sendBack);
    }
}

void MsgParser::processBuffer(const QByteArray &buffer)
{
    // 这里回传，当有多个语句合在一起时，接收端只有第一个是带了报文头[BlackTCP]
    // if (m_postback)
    // emit postbackData(buffer);
    m_lastResult = nullptr;
    QByteArrayList bufferList;
    if (buffer.contains(LF))
        bufferList = buffer.split(LF);
    else
        bufferList = buffer.split(CR1);
    int n = bufferList.count();
    if (n == 0)
        return;
    else if (n == 1)
        m_lastMsg.append(buffer.trimmed());
    else
    {
        QByteArray s = m_lastMsg + bufferList.first();
        parse(s.trimmed());
        for (int i = 1; i < n - 1; i++)
        {
            parse(bufferList.at(i).trimmed());
        }
        m_lastMsg = bufferList.last().trimmed();
    }
}

void MsgParser::parse(const QByteArray &msg)
{
    if (m_postback)
        emit postbackData(msg);
    TalkType talkId = parseTalkId(msg);
    if (talkId == TalkType::TT_Other)
        return;
    QByteArray nmea = msg.mid(3, 3);
    // if (GLOG)
    // GLOG->info("MsgParser::parse--{}-{}----:{}", int(talkId), nmea, msg.toStdString());
#if 0

    if (talkId == TalkType::TT_BD)
    {
        m_deviceUpdateTime[DeviceType::BD] = GTime::getUtcTime_s();
        m_BDLastTime = GTime::getLocalTime().toMSecsSinceEpoch();
        if (state != 0)
        {
            state = 0;
            emit posStateChange(state);
        }
    }
    else if (talkId == TalkType::TT_GP || talkId == TalkType::TT_GN)
    {
        m_deviceUpdateTime[DeviceType::Gps] = GTime::getUtcTime_s();
        m_GPLastTime = GTime::getLocalTime().toMSecsSinceEpoch();
#if 0
        int time = ALLSETTINGS.systemSetting.validtime.BDtime;
        qint64 nowtime = GTime::getLocalTime().toMSecsSinceEpoch();
        if (m_BDLastTime != -9999)
            if (nowtime - m_BDLastTime < time * 60000)
                return;
        if (state != 1)
        {
            state = 1;
            emit posStateChange(state);
        }
#endif
    }
    else if (talkId == TalkType::TT_AI)
    {
        m_deviceUpdateTime[DeviceType::Ais] = GTime::getUtcTime_s();
        m_AISLastTime = GTime::getLocalTime().toMSecsSinceEpoch();
#if 0
        int bdtime = ALLSETTINGS.systemSetting.validtime.BDtime;
        qint64 nowtime = GTime::getLocalTime().toMSecsSinceEpoch();
        if (nmea == "VDO")
        {
            if (m_BDLastTime != -9999)
            {
                if (nowtime - m_BDLastTime < bdtime * 60000)
                    return;
                else
                {
                    int gptime = ALLSETTINGS.systemSetting.validtime.GPtime;
                    if (m_GPLastTime != -9999)
                        if (nowtime - m_GPLastTime < gptime * 60000)
                            return;
                }
            }
            int gptime = ALLSETTINGS.systemSetting.validtime.GPtime;
            if (m_GPLastTime != -9999)
                if (nowtime - m_GPLastTime < gptime * 60000)
                    return;
            if (state != 2)
            {
                state = 2;
                emit posStateChange(state);
            }
        }
#endif
    }
    else if (talkId == TalkType::TT_HC)
    {
        m_deviceUpdateTime[DeviceType::Compass] = GTime::getUtcTime_s();
    }
    else if (talkId == TalkType::TT_PA)
    {
        // qInfo() << "MsgParser::parse ============ 姿态仪 ==============" << msg;
        m_deviceUpdateTime[DeviceType::Motion] = GTime::getUtcTime_s();
    }
    else if (talkId == TalkType::TT_RA)
    {
        m_deviceUpdateTime[DeviceType::Radar] = GTime::getUtcTime_s();
    }
    else if (talkId == TalkType::TT_SD)
    {
        m_deviceUpdateTime[DeviceType::Deep] = GTime::getUtcTime_s();
    }
    else if (talkId == TalkType::TT_WI)
    {
        m_deviceUpdateTime[DeviceType::Wind] = GTime::getUtcTime_s();
    }
#endif
    // 正常是需要如上区分不同设备，黑匣子不需要
    m_deviceUpdateTime[DeviceType::Ais] = GTime::getUtcTime_s();

    if (msg.at(3) == 'A')
    {
        if (msg.at(4) == 'L')
        {
            if (msg.at(5) == 'R')
            {
                // 黑匣子不需要
                //  parseALR(msg);
            }
            else if (msg.at(5) == 'C')
                parseALC(msg);
            else if (msg.at(5) == 'F')
                parseALF(msg);
        }
        else if (msg.at(4) == 'C')
        {
            if (msg.at(5) == 'K')
                parseACK(msg);
            else if (msg.at(5) == 'N')
                parseACN(msg);
        }
    }
    else if (msg.at(3) == 'V')
    {
        if (msg.at(4) == 'D')
        {
            if (msg.at(5) == 'M')
                parseAIS(msg, false);
            else if (msg.at(5) == 'O')
                parseAIS(msg, true);
        }
        else if (msg.at(4) == 'T')
        {
            if (msg.at(5) == 'G')
                parseVTG(msg);
        }
    }
    else if (msg.at(3) == 'Z')
    {
        if (msg.at(4) == 'D')
        {
            if (msg.at(5) == 'A')
                parseZDA(msg);
        }
    }
    else if (msg.at(3) == 'D')
    {
        if (msg.at(4) == 'B')
            parseDBT(msg);
        if (msg.at(4) == 'P')
            parseDPT(msg);
    }
    else if (msg.at(3) == 'H')
    {
        if (msg.at(4) == 'D')
        {
            if (msg.at(5) == 'T')
                parseHDT(msg);
            else if (msg.at(6) == 'G')
                parseHDG(msg);
        }
    }
    else if (msg.at(3) == 'G')
    {
        if (msg.at(4) == 'G')
        {
            if (msg.at(5) == 'A')
                parseGGA(msg);
        }
        else if (msg.at(4) == 'L')
        {
            if (msg.at(5) == 'L')
                parseGLL(msg);
        }
        // else if(msg.at(4)=='S')
        // {
        //     if(msg.at(5)=='A')
        //         parseGSA(msg);
        //     else if(msg.at(5)=='V')
        //         parseGSV(msg);
        // }
        else if (msg.at(4) == 'N')
        {
            if (msg.at(5) == 'S')
                parseGNS(msg);
        }
    }
    else if (msg.at(3) == 'R')
    {
        if (msg.at(4) == 'M')
        {
            if (msg.at(5) == 'C')
                parseRMC(msg);
            else if (msg.at(5) == 'B')
            {
                // parseRMB(msg);
            }
        }
    }
    // else if (msg.at(3) == 'T')
    // {
    //     if (msg.at(4) == 'C')
    //     {
    //         if (msg.at(5) == 'I')
    //             parseTCI(msg);
    //     }
    //     else if (msg.at(4) == 'T')
    //     {
    //         if (msg.at(5) == 'M')
    //             parseTTM(msg);
    //     }
    //     else if (msg.at(4) == 'L')
    //     {
    //         if (msg.at(5) == 'L')
    //             parseTLL(msg);
    //     }
    // }
}

TalkType MsgParser::parseTalkId(const QByteArray &msg)
{
    TalkType talkId = TalkType::TT_Other;
    NMEAType nmeaType = NMEAType::NT_Other;
    // qInfo() << "parseTalkId msg==================" << msg;
    switch (msg.at(1))
    {
    case 'A':
        switch (msg.at(2))
        {
        case 'G':
            talkId = TalkType::TT_AG;
            break;
        case 'P':
            talkId = TalkType::TT_AP;
            break;
        case 'I':
            talkId = TalkType::TT_AI;
            break;
        default:
            break;
        }
        break;
    case 'B':
        switch (msg.at(2))
        {
        case 'D':
            talkId = TalkType::TT_BD;
            break;
        default:
            break;
        }
        break;
        ;

    case 'C':
        switch (msg.at(2))
        {
        case 'C':
            talkId = TalkType::TT_CC;
            break;
        case 'D':
            talkId = TalkType::TT_CD;
            break;
        case 'M':
            talkId = TalkType::TT_CM;
            break;
        case 'S':
            talkId = TalkType::TT_CS;
            break;
        case 'T':
            talkId = TalkType::TT_CT;
            break;
        case 'V':
            talkId = TalkType::TT_CV;
            break;
        case 'X':
            talkId = TalkType::TT_CX;
            break;
        default:
            break;
        }
        break;

    case 'D':
        switch (msg.at(2))
        {
        case 'E':
            talkId = TalkType::TT_DE;
            break;
        case 'F':
            talkId = TalkType::TT_DF;
            break;
        default:
            break;
        }
        break;

    case 'E':
        switch (msg.at(2))
        {
        case 'C':
            talkId = TalkType::TT_EC;
            break;
        case 'P':
            talkId = TalkType::TT_EP;
            break;
        case 'R':
            talkId = TalkType::TT_ER;
            break;
        default:
            break;
        }
        break;
    case 'G':
        switch (msg.at(2))
        {
        case 'P':
            talkId = TalkType::TT_GP;
            break;
        case 'N':
            talkId = TalkType::TT_GN;
            break;
        default:
            break;
        }
        break;
    case 'H':
        switch (msg.at(2))
        {
        case 'C':
            talkId = TalkType::TT_HC;
            break;
        case 'E':
            talkId = TalkType::TT_HE;
            break;
        case 'N':
            talkId = TalkType::TT_HN;
            break;
        default:
            break;
        }
        break;
    case 'I':
        switch (msg.at(2))
        {
        case 'I':
            talkId = TalkType::TT_II;
            break;
        case 'N':
            talkId = TalkType::TT_IN;
            break;
        default:
            break;
        }
        break;
    case 'L':
        switch (msg.at(2))
        {
        case 'A':
            talkId = TalkType::TT_LA;
            break;
        case 'C':
            talkId = TalkType::TT_LC;
            break;
        default:
            break;
        }
        break;
    case 'M':
        switch (msg.at(2))
        {
        case 'P':
            talkId = TalkType::TT_MP;
            break;
        default:
            break;
        }
        break;
    case 'O':
        switch (msg.at(2))
        {
        case 'M':
            talkId = TalkType::TT_OM;
            break;
        case 'S':
            talkId = TalkType::TT_OS;
            break;
        default:
            break;
        }
        break;
    case 'P':
        switch (msg.at(2))
        {
        case 'A':
            talkId = TalkType::TT_PA;
            break;
        default:
            break;
        }
        break;
    case 'R':
        switch (msg.at(2))
        {
        case 'A':
            talkId = TalkType::TT_RA;
            break;
        default:
            break;
        }
        break;
    case 'S':
        switch (msg.at(2))
        {
        case 'D':
            talkId = TalkType::TT_SD;
            break;
        case 'N':
            talkId = TalkType::TT_SN;
            break;
        case 'S':
            talkId = TalkType::TT_SS;
            break;
        default:
            break;
        }
        break;
    case 'T':
        switch (msg.at(2))
        {
        case 'I':
            talkId = TalkType::TT_TI;
            break;
        case 'R':
            talkId = TalkType::TT_TR;
            break;
        default:
            break;
        }
        break;
    case 'V':
        switch (msg.at(2))
        {
        case 'D':
            talkId = TalkType::TT_VD;
            break;
        case 'M':
            talkId = TalkType::TT_VM;
            break;
        case 'W':
            talkId = TalkType::TT_VW;
            break;
        default:
            break;
        }
        break;
    case 'W':
        switch (msg.at(2))
        {
        case 'I':
            talkId = TalkType::TT_WI;
            break;
        default:
            break;
        }
        break;
    case 'Y':
        switch (msg.at(2))
        {
        case 'C':
            talkId = TalkType::TT_YC;
            break;
        case 'D':
            talkId = TalkType::TT_YD;
            break;
        case 'F':
            talkId = TalkType::TT_YF;
            break;
        case 'L':
            talkId = TalkType::TT_YL;
            break;
        case 'P':
            talkId = TalkType::TT_YP;
            break;
        case 'R':
            talkId = TalkType::TT_YR;
            break;
        case 'T':
            talkId = TalkType::TT_YT;
            break;
        case 'V':
            talkId = TalkType::TT_YV;
            break;
        case 'X':
            talkId = TalkType::TT_YX;
            break;
        default:
            break;
        }
        break;
    case 'Z':
        switch (msg.at(2))
        {
        case 'A':
            talkId = TalkType::TT_ZA;
            break;
        case 'C':
            talkId = TalkType::TT_ZC;
            break;
        case 'Q':
            talkId = TalkType::TT_ZQ;
            break;
        case 'V':
            talkId = TalkType::TT_ZV;
            break;
        default:
            break;
        }
        break;
    default:
        break;
    }
    return talkId;
}

void MsgParser::parseACK(const QByteArray &msg)
{
}

// $AIALR,175743.41,035,A,V,AIS: No valid ROT information*61
void MsgParser::parseALR(const QByteArray &msg)
{
    const QByteArrayList msgs = msg.split(',');
    if (msgs.count() != 6)
        return;

    ALR *palr = new ALR;
    palr->ctime = msgs[1];
    palr->id = msgs.at(2).toInt();
    QString ac = msgs.at(3);
    QString alarmcondition = msgs.at(3);
    if (alarmcondition == 'A')
        palr->alarmCondition = AlarmCondition::ThresholdExceeded;
    else if (alarmcondition == 'V')
        palr->alarmCondition = AlarmCondition::NotExceeded;
    else
        palr->alarmCondition = AlarmCondition::Unknown;

    QString ack = msgs.at(4);
    if (ack == "A")
        palr->alarmAcknowledgeState = AlarmAcknowledgeState::Acknownledge;
    else if (ack == "V")
        palr->alarmAcknowledgeState = AlarmAcknowledgeState::Unacknowledged;
    else
        palr->alarmAcknowledgeState = AlarmAcknowledgeState::Unknown;

    palr->text = msgs.at(5).split('*')[0];
    emit ALRFinished(palr);
}

// Utc时间和本地时区
// Example:  $GPZDA,234500,09,06,1995,-12,45*6C
void MsgParser::parseZDA(const QByteArray &msg)
{
    const QByteArrayList msgs = msg.split(',');
    if (msgs.count() != 7)
        return;

    int cyear = msgs.at(4).toInt();
    int cmonth = msgs.at(3).toInt();
    int cday = msgs.at(2).toInt();

    int chour = msgs.at(1).left(2).toInt();
    int cminute = msgs.at(1).mid(2, 2).toInt();
    int csecond = msgs.at(1).mid(4, 2).toInt();

    int cmsecond = 0;

    QDateTime ctime(QDate(cyear, cmonth, cday), QTime(chour, cminute, csecond, cmsecond), QTimeZone::utc());
    int czoneMinute = msgs.at(6).left(2).toInt();
    int czoneHour = msgs.at(5).toInt();

    // GTime中使用setUtcTime中的setTimeSpec(UTC)可以抵消下列语句
    int secs = qAbs(czoneHour) * 60 * 60 + qAbs(czoneMinute) * 60;
    if (czoneHour > 0)
        secs = -secs;
    ZDA *pzda = new ZDA;
    pzda->ctime = ctime.toSecsSinceEpoch();
    pzda->zoneDiff = secs;

    emit zdaFinished(pzda);
}

void MsgParser::parseAIS(const QByteArray &msg, bool vdo)
{
    const QByteArrayList msgs = msg.split(',');
    if (msgs.count() != 7)
        return;

    // static QByteArray mainParties[10];

    int totalNumber = msgs.at(1).toInt();
    int sIndex = msgs.at(2).toInt();
    int sId = msgs.at(3).toInt();

    QByteArray mainPart;

    if (totalNumber == 1)
    {
        mainPart = msgs.at(5);
    }
    else
    {
        msManage.insert(sId, totalNumber, sIndex, msgs.at(5));
        if (msManage.isReady(sId))
            mainPart = msManage.getSentence(sId);
        else
            return;
    }
    SixBitString sb(mainPart);
    int pos = 1;
    int msgId = sb.getInt(pos, 6);
    if (msgId == 1 || msgId == 2 || msgId == 3)
        parseAIS_1(sb, vdo);
    else if (msgId == 5)
        parseAIS_5(sb, vdo);
    else if (msgId == 4 || msgId == 11) // parseVDM
        parseAIS_4(sb, vdo);
    else if (msgId == 14)
    {
        // 黑匣子不需要
        // parseAIS_14(sb, vdo);
    }
    else if (msgId == 18)
        parseAIS_18(sb, vdo);
    else if (msgId == 24)
        parseAIS_24(sb, vdo);
}

void MsgParser::parseAIS_1(SixBitString &sb, bool vdo)
{
    int pos = 1;
    int msgId = sb.getInt(pos, 6);
    pos += 6;
    // qInfo() << "sb.getBitCount()============parseAIS_1=================" << sb.getBitCount();
    if (sb.getBitCount() != 168)
        return;

    // QSharedPointer<AIS_1> ais(new AIS_1);
    AIS_1 *ais = new AIS_1;
    auto repeat = sb.getInt(pos, 2);
    switch (repeat)
    {
    case 0:
        ais->Repeat = ForwardIndicator::Default;
        break;
    case 3:
        ais->Repeat = ForwardIndicator::NoLongerForward;
        break;
    default:
        ais->Repeat = ForwardIndicator::Unknown;
        break;
    }
    pos += 2;
    ais->Mmsi = sb.getInt(pos, 30);
    pos += 30;
    auto status = sb.getInt(pos, 4);
    ais->Status = NavigationalState(status);
    pos += 4;
    // 注意转弯速率ROT的转换
    ais->Rotais = sb.getInt(pos, 8, true);
    if (ais->Rotais != 127 && ais->Rotais != 128 && ais->Rotais != -127)
    {
        ais->Rot = qPow(ais->Rotais / 4.733, 2);
        if (ais->Rotais < 0)
            ais->Rot = -ais->Rot;
    }

    pos += 8;
    int sog = sb.getInt(pos, 10);
    if (sog != 1023)
        ais->SOG = sog * 0.1;
    pos += 10;
    ais->Accuracy = sb.getInt(pos, 1);
    pos += 1;
    ais->Lon = sb.getLon(pos, 28);
    pos += 28;
    ais->Lat = sb.getLat(pos, 27);
    pos += 27;
    int cog = sb.getInt(pos, 12);
    if (cog != 3600)
        ais->COG = cog * 0.1;
    pos += 12;
    int heading = sb.getInt(pos, 9);
    if (heading < 360)
        ais->Heading = heading;
    pos += 9;
    ais->UTCsecond = sb.getInt(pos, 6);
    pos += 6;
    auto maneuver = sb.getInt(pos, 2);
    switch (maneuver)
    {
    case 0:
        ais->Maneuver = ManeuverType::Default;
        break;
    case 1:
        ais->Maneuver = ManeuverType::NoSpecificManipulation;
        break;
    case 2:
        ais->Maneuver = ManeuverType::SpecificManipulation;
        break;
    default:
        ais->Maneuver = ManeuverType::Default;
        break;
    }
    pos += 5;
    auto raim = sb.getInt(pos, 1);
    pos += 1;
    switch (raim)
    {
    case 0:
        ais->Raim = RaimFlag::Default;
        break;
    case 1:
        ais->Raim = RaimFlag::RAIMUseing;
        break;
    default:
        ais->Raim = RaimFlag::Default;
        break;
    }
    if (msgId == 1 || msgId == 2)
    {
        ais->sotdma.sync = sb.getInt(pos, 2);
        pos += 2;
        ais->sotdma.TimeSlotTimeout = sb.getInt(pos, 3);
        pos += 3;
        ais->sotdma.SMessage = sb.getInt(pos, 14);
    }
    else if (msgId == 3)
    {
        ais->itdma.sync = sb.getInt(pos, 2);
        pos += 2;
        ais->itdma.TimeSlotIncremental = sb.getInt(pos, 13);
        pos += 13;
        ais->itdma.NumberOfTime = sb.getInt(pos, 3);
        pos += 3;
        ais->itdma.flag = sb.getInt(pos, 1);
    }
    m_lastResult = ais;
    emit ais1Finished(ais, vdo);
}

void MsgParser::parseAIS_5(SixBitString &sb, bool vdo)
{
    // dbg(mainpart, sb.getBitCount());
    // qInfo() << "sb.getBitCount()=======parseAIS_5======================" << sb.getBitCount();
    if (sb.getBitCount() != 426)
        return; // 标准是426，有时会加进来\n，有时也会有多个字符
    // QSharedPointer<AIS_5> ais(new AIS_5);
    AIS_5 *ais = new AIS_5;
    int pos = 7;
    auto repeat = sb.getInt(pos, 2);
    switch (repeat)
    {
    case 0:
        ais->Repeat = ForwardIndicator::Default;
        break;
    case 3:
        ais->Repeat = ForwardIndicator::NoLongerForward;
        break;
    default:
        ais->Repeat = ForwardIndicator::Unknown;
        break;
    }
    pos += 2;
    ais->Mmsi = sb.getInt(pos, 30);
    pos += 30;

    auto aisVersion = sb.getInt(pos, 2);
    switch (aisVersion)
    {
    case 0:
        ais->AisVersion = AISVersion::RM13711;
        break;
    case 1:
        ais->AisVersion = AISVersion::RM13713;
        break;
    default:
        ais->AisVersion = AISVersion::Unknown;
        break;
    }
    pos += 2;

    ais->IMONumber = sb.getInt(pos, 30);
    pos += 30;

    ais->CallSign = sb.getStr(pos, 42);
    pos += 42;

    ais->ShipName = sb.getStr(pos, 120);
    pos += 120;

    ais->ShipType = sb.getInt(pos, 8);
    pos += 8;

    ais->ToBow = sb.getInt(pos, 9);
    pos += 9;
    ais->ToStern = sb.getInt(pos, 9);
    pos += 9;
    ais->ToPort = sb.getInt(pos, 6);
    pos += 6;
    ais->ToStarboard = sb.getInt(pos, 6);
    pos += 6;

    auto electronicDeviceTheType = sb.getInt(pos, 4);
    switch (electronicDeviceTheType)
    {
    case 0:
        ais->EDeviceTheType = ElectronicDeviceTheType::Defalut;
        break;
    case 1:
        ais->EDeviceTheType = ElectronicDeviceTheType::GPS;
        break;
    case 2:
        ais->EDeviceTheType = ElectronicDeviceTheType::GLONASS;
        break;
    case 3:
        ais->EDeviceTheType = ElectronicDeviceTheType::GPSAndGLONASS;
        break;
    case 4:
        ais->EDeviceTheType = ElectronicDeviceTheType::LoranC;
        break;
    case 5:
        ais->EDeviceTheType = ElectronicDeviceTheType::Chayka;
        break;
    case 6:
        ais->EDeviceTheType = ElectronicDeviceTheType::IntegrateSystem;
        break;
    case 7:
        ais->EDeviceTheType = ElectronicDeviceTheType::Researching;
        break;
    case 8:
        ais->EDeviceTheType = ElectronicDeviceTheType::Galileo;
        break;
    case 15:
        ais->EDeviceTheType = ElectronicDeviceTheType::GNSSIn;
        break;
    default:
        ais->EDeviceTheType = ElectronicDeviceTheType::Defalut;
        break;
    }
    pos += 4;

    ais->Month = sb.getInt(pos, 4);
    pos += 4;
    ais->Day = sb.getInt(pos, 5);
    pos += 5;
    ais->Hour = sb.getInt(pos, 5);
    pos += 5;
    ais->Minute = sb.getInt(pos, 6);
    pos += 6;

    ais->Draught = sb.getInt(pos, 8) * 0.1;
    pos += 8;

    ais->DestinationName = sb.getStr(pos, 120);
    pos += 120;

    auto dte = sb.getInt(pos, 1);
    switch (dte)
    {
    case 0:
        ais->DTE = DTEState::Available;
        break;
    case 1:
        ais->DTE = DTEState::Default;
        break;
    default:
        ais->DTE = DTEState::Default;
        break;
    }
    m_lastResult = ais;
    emit ais5Finished(ais, vdo);
}

void MsgParser::parseAIS_4(SixBitString &sb, bool vdo)
{
    int pos = 1;
    int msgId = sb.getInt(pos, 6);
    pos += 6;
    // qInfo() << "sb.getBitCount()============parseAIS_1=================" << sb.getBitCount();
    if (sb.getBitCount() != 168)
        return;

    AIS_4 *ais = new AIS_4;
    auto repeat = sb.getInt(pos, 2);
    switch (repeat)
    {
    case 0:
        ais->Repeat = ForwardIndicator::Default;
        break;
    case 3:
        ais->Repeat = ForwardIndicator::NoLongerForward;
        break;
    default:
        ais->Repeat = ForwardIndicator::Unknown;
        break;
    }
    pos += 2;
    ais->Mmsi = sb.getInt(pos, 30);
    pos += 30;
    ais->Year = sb.getInt(pos, 14);
    pos += 14;
    ais->Month = sb.getInt(pos, 4);
    pos += 4;
    ais->Day = sb.getInt(pos, 5);
    pos += 5;
    ais->Hour = sb.getInt(pos, 5);
    pos += 5;
    ais->Minute = sb.getInt(pos, 6);
    pos += 6;
    ais->Second = sb.getInt(pos, 6);
    pos += 6;
    ais->Accuracy = sb.getInt(pos, 1);
    pos += 1;
    ais->Lon = sb.getLon(pos, 28);
    pos += 28;
    ais->Lat = sb.getLat(pos, 27);
    pos += 27;

    auto electronicDeviceTheType = sb.getInt(pos, 4);
    switch (electronicDeviceTheType)
    {
    case 0:
        ais->electronicDeviceTheType = ElectronicDeviceTheType::Defalut;
        break;
    case 1:
        ais->electronicDeviceTheType = ElectronicDeviceTheType::GPS;
        break;
    case 2:
        ais->electronicDeviceTheType = ElectronicDeviceTheType::GLONASS;
        break;
    case 3:
        ais->electronicDeviceTheType = ElectronicDeviceTheType::GPSAndGLONASS;
        break;
    case 4:
        ais->electronicDeviceTheType = ElectronicDeviceTheType::LoranC;
        break;
    case 5:
        ais->electronicDeviceTheType = ElectronicDeviceTheType::Chayka;
        break;
    case 6:
        ais->electronicDeviceTheType = ElectronicDeviceTheType::IntegrateSystem;
        break;
    case 7:
        ais->electronicDeviceTheType = ElectronicDeviceTheType::Researching;
        break;
    case 8:
        ais->electronicDeviceTheType = ElectronicDeviceTheType::Galileo;
        break;
    case 15:
        ais->electronicDeviceTheType = ElectronicDeviceTheType::GNSSIn;
        break;
    default:
        ais->electronicDeviceTheType = ElectronicDeviceTheType::Defalut;
        break;
    }
    pos += 4;
    ais->control = sb.getInt(pos, 1);
    pos += 10;
    auto raim = sb.getInt(pos, 1);

    switch (raim)
    {
    case 0:
        ais->Raim = RaimFlag::Default;
        break;
    case 1:
        ais->Raim = RaimFlag::RAIMUseing;
        break;
    default:
        ais->Raim = RaimFlag::Default;
        break;
    }
    pos += 1;
    ais->sotdma.sync = sb.getInt(pos, 2);
    pos += 2;
    ais->sotdma.TimeSlotTimeout = sb.getInt(pos, 3);
    pos += 3;
    ais->sotdma.SMessage = sb.getInt(pos, 14);
    m_lastResult = ais;
    emit ais4Finished(ais, vdo);
}

void MsgParser::parseAIS_14(SixBitString &sb, bool vdo)
{
    AIS_14 *ais = new AIS_14;
    int pos = 7;
    auto repeat = sb.getInt(pos, 2);
    switch (repeat)
    {
    case 0:
        ais->Repeat = ForwardIndicator::Default;
        break;
    case 3:
        ais->Repeat = ForwardIndicator::NoLongerForward;
        break;
    default:
        ais->Repeat = ForwardIndicator::Unknown;
        break;
    }
    pos += 2;
    ais->Mmsi = sb.getInt(pos, 30);

    pos += 32;
    ais->text = sb.getStr(pos, sb.getBitCount() - 40);
    m_lastResult = ais;
    emit ais14Finished(ais, vdo);
}

void MsgParser::parseAIS_18(SixBitString &sb, bool vdo)
{
    if (sb.getBitCount() < 168)
        return; // 标准是168，有时会加进来\n，有时也会有多个字符
    AIS_18 *ais = new AIS_18;
    int pos = 7;
    auto repeat = sb.getInt(pos, 2);
    switch (repeat)
    {
    case 0:
        ais->Repeat = ForwardIndicator::Default;
        break;
    case 3:
        ais->Repeat = ForwardIndicator::NoLongerForward;
        break;
    default:
        ais->Repeat = ForwardIndicator::Unknown;
        break;
    }
    pos += 2;
    ais->Mmsi = sb.getInt(pos, 30);
    pos += 38;
    ais->speed = sb.getInt(pos, 10) * 0.1;
    pos += 10;
    ais->accuracy = sb.getInt(pos, 1);
    pos += 1;
    ais->lon = sb.getLon(pos, 28);
    pos += 28;
    ais->lat = sb.getLat(pos, 27);
    pos += 27;
    ais->course = sb.getInt(pos, 12) * 0.1;
    pos += 12;
    ais->heading = sb.getInt(pos, 9);
    pos += 9;
    ais->second = sb.getInt(pos, 6);
    pos += 6;
    ais->regional = sb.getInt(pos, 2);
    pos += 2;
    ais->cs = sb.getInt(pos, 1);
    pos += 1;
    ais->display = sb.getInt(pos, 1);
    pos += 1;
    ais->dsc = sb.getInt(pos, 1);
    pos += 1;
    ais->band = sb.getInt(pos, 1);
    pos += 1;
    ais->msg22 = sb.getInt(pos, 1);
    pos += 1;
    ais->assigned = sb.getInt(pos, 1);
    pos += 1;
    ais->raim = sb.getInt(pos, 1);
    pos += 1;
    ais->radio = sb.getInt(pos, 1);
    m_lastResult = ais;
    emit ais18Finished(ais, vdo);
}

void MsgParser::parseAIS_24(SixBitString &sb, bool vdo)
{
    AIS_24 *ais = new AIS_24;
    int pos = 7;
    auto repeat = sb.getInt(pos, 2);
    switch (repeat)
    {
    case 0:
        ais->Repeat = ForwardIndicator::Default;
        break;
    case 3:
        ais->Repeat = ForwardIndicator::NoLongerForward;
        break;
    default:
        ais->Repeat = ForwardIndicator::Unknown;
        break;
    }
    pos += 2;
    ais->Mmsi = sb.getInt(pos, 30);
    pos += 30;
    int partno = sb.getInt(pos, 2);
    ais->partno = partno;
    pos += 2;
    if (partno == 0)
    {
        ais->shipname = sb.getStr(pos, 120);
    }
    else
    {
        ais->shiptype = sb.getInt(pos, 8);
        pos += 8;
        ais->vendorid = sb.getStr(pos, 18);
        pos += 18;
        ais->model = sb.getInt(pos, 4);
        pos += 4;
        ais->serial = sb.getInt(pos, 20);
        pos += 20;
        ais->callsign = sb.getStr(pos, 42);
        pos += 42;
        ais->to_bow = sb.getInt(pos, 9);
        pos += 9;
        ais->to_stern = sb.getInt(pos, 9);
        pos += 9;
        ais->to_port = sb.getInt(pos, 6);
        pos += 6;
        ais->to_starboard = sb.getInt(pos, 6);
        pos += 6;
        auto electronicDeviceTheType = sb.getInt(pos, 4);
        switch (electronicDeviceTheType)
        {
        case 0:
            ais->EDeviceTheType = ElectronicDeviceTheType::Defalut;
            break;
        case 1:
            ais->EDeviceTheType = ElectronicDeviceTheType::GPS;
            break;
        case 2:
            ais->EDeviceTheType = ElectronicDeviceTheType::GLONASS;
            break;
        case 3:
            ais->EDeviceTheType = ElectronicDeviceTheType::GPSAndGLONASS;
            break;
        case 4:
            ais->EDeviceTheType = ElectronicDeviceTheType::LoranC;
            break;
        case 5:
            ais->EDeviceTheType = ElectronicDeviceTheType::Chayka;
            break;
        case 6:
            ais->EDeviceTheType = ElectronicDeviceTheType::IntegrateSystem;
            break;
        case 7:
            ais->EDeviceTheType = ElectronicDeviceTheType::Researching;
            break;
        case 8:
            ais->EDeviceTheType = ElectronicDeviceTheType::Galileo;
            break;
        case 15:
            ais->EDeviceTheType = ElectronicDeviceTheType::GNSSIn;
            break;
        default:
            ais->EDeviceTheType = ElectronicDeviceTheType::Defalut;
            break;
        }
    }
    m_lastResult = ais;
    emit ais24Finished(ais, vdo);
}

void MsgParser::parseHDT(const QByteArray &msg)
{
    const QByteArrayList msgs = msg.split(',');
    if (msgs.count() != 3)
        return;
    emit HDTFinished(msgs[1].toDouble());
}

void MsgParser::parseHDG(const QByteArray &msg)
{
    const QByteArrayList msgs = msg.split(',');
    if (msgs.count() != 6)
        return;
    HDG *hdg = new HDG;
    hdg->heading = msgs[1].toDouble();
    hdg->cicha = msgs[2].toDouble();
    if (msgs[3] == "W")
    {
        hdg->cicha = hdg->cicha * (-1);
    }
    hdg->zicha = msgs[4].toDouble();
    if (msgs[5] == "W")
    {
        hdg->zicha = hdg->zicha * (-1);
    }
    emit HDGFinished(hdg);
}

void MsgParser::parseDPT(const QByteArray &msg)
{
    const QByteArrayList msgs = msg.split(',');
    if (msgs.count() != 4)
        return;
    DPT *dpt = new DPT;
    dpt->depth = msgs[1].toDouble();
    dpt->offset = msgs[2].toDouble();
    dpt->maxrange = msgs[3].toDouble();
    emit DPTFinished(dpt);
}

void MsgParser::parseDBT(const QByteArray &msg)
{
    const QByteArrayList msgs = msg.split(',');
    if (msgs.count() != 7)
        return;

    emit DBTFinished(msgs[3].toDouble());
}

void MsgParser::parseTTM(const QByteArray &msg)
{
    // qInfo() << " MsgParser::parseTTM==================" << msg;
    const QByteArrayList msgs = msg.split(',');
    if (msgs.count() != 16)
        return;

    TTM *ttm = new TTM;
    ttm->id = msgs.at(1).toInt();
    if (msgs.at(2) != "")
        ttm->distance = msgs.at(2).toDouble();
    if (msgs.at(3) != "")
        ttm->bearing = msgs.at(3).toDouble();
    // TODO:报文中的角度朝向，T(true)和R(relative)不清楚是什么意思
    // if (msgs.at(4) != "T")
    //     ttm->bearing = -ttm->bearing;
    if (msgs.at(5) != "")
        ttm->speed = msgs.at(5).toDouble();
    if (msgs.at(6) != "")
        ttm->course = msgs.at(6).toDouble();
    // if (msgs.at(7) != "T")
    //     ttm->course = -ttm->course;
    if (msgs.at(8) != "")
        ttm->dcpa = msgs.at(8).toDouble();
    if (msgs.at(9) != "")
        ttm->tcpa = msgs.at(9).toDouble();
    // TODO:报文中的距离速度单位，N是海里和节，K应该是公里，S不清楚代表什么
    if (msgs.at(10) != "N")
    {
        ttm->distance *= 1000;
        ttm->speed /= 1.852;
        ttm->dcpa *= 1000;
    }
    else
    {
        ttm->distance *= 1852;
        ttm->dcpa *= 1852;
    }
    if (msgs.at(11) != "")
        ttm->name = msgs.at(11);
    if (msgs.at(12) == "T")
        ttm->status = 2;
    else if (msgs.at(12) == "L")
        ttm->status = 0;
    else
        ttm->status = 1;
    if (msgs.at(13) == "R")
        ttm->refrence = true;
    ttm->time = msgs.at(14);

    emit TTMFinished(ttm);
}

void MsgParser::parseTLL(const QByteArray &msg)
{
    const QByteArrayList msgs = msg.split(',');
    if (msgs.count() != 10)
        return;
    TLL *tll = new TLL;
    tll->id = msgs.at(1).toInt();

    tll->lat = msgs.at(2).toDouble();
    if (msgs.at(3) == "S")
        tll->lat = -tll->lat;
    tll->lon = msgs.at(4).toDouble();
    if (msgs.at(5) == "W")
        tll->lon = -tll->lon;
    tll->name = msgs.at(6);
    tll->time = msgs.at(7);
    if (msgs.at(8) == "T")
        tll->status = 2;
    else if (msgs.at(8) == "L")
        tll->status = 0;
    else
        tll->status = 1;
    tll->refrence = (msgs.at(9).at(0) == 'R');
    emit TLLFinished(tll);
}

void MsgParser::parseACN(const QByteArray &msg)
{
}

void MsgParser::parseALC(const QByteArray &msg)
{
}

void MsgParser::parseALF(const QByteArray &msg)
{
}

int MsgParser::getSatelliteType(const QByteArray &code)
{
    int returnInt = -1;
    QString prefString = code.mid(1, 2);

    if (prefString == "GP")
    {
        returnInt = 1;
    }
    else if (prefString == "GN")
    {
        returnInt = 2;
    }
    else if (prefString == "BD")
    {
        returnInt = 0;
    }

    return returnInt;
}

void MsgParser::parseGGA(const QByteArray &msg)
{
    // Example:  $GPGGA,092204.999,4250.5589,S,14718.5084,E,1,04,24.4,19.7,M,,,,0000*1F
    const QByteArrayList msgs = msg.split(',');
    if (msgs.count() != 15)
        return;
    GGA *gga = new GGA;
    gga->status = msgs[6].toInt();
    if (gga->status == 0)
        return;
    gga->type = getSatelliteType(msgs[0]);
    gga->utc = CommonUtil::getUtc(msgs[1], 1);
    gga->lat = LonLatUtil::getLat(msgs.at(2), msgs.at(3));
    gga->lon = LonLatUtil::getLon(msgs.at(4), msgs.at(5));

    gga->satellitecount = msgs[7].toInt();
    gga->hdop = msgs[8].toDouble();
    gga->altitude = msgs[9].toDouble();
    gga->altitudeunit = msgs[10];
    gga->heightanomaly = msgs[11].toInt();
    gga->heightanomalyunit = msgs[12].toInt();
    gga->difference = msgs[13].toInt();

    if (msgs[14].left(1) == "*")
    {
        gga->differenceid = "";
    }
    else
    {
        gga->differenceid = msgs[14].left(4);
    }
    m_lastResult = gga;
    emit GGAFinished(gga);
}

void MsgParser::parseGLL(const QByteArray &msg)
{
    // Example:  $GPGLL,3601.5960,N,12013.3982,E,054103.00,A,A*65
    const QByteArrayList msgs = msg.split(',');
    if (msgs.count() != 8)
        return;
    GLL *gll = new GLL;
    gll->type = getSatelliteType(msgs[0]);
    gll->lat = LonLatUtil::getLat(msgs.at(1), msgs.at(2));
    gll->lon = LonLatUtil::getLon(msgs.at(3), msgs.at(4));
    gll->utc = CommonUtil::getUtc(msgs[5], 0);
    gll->status = msgs[6];

    if (msgs[7].left(1) == "*")
    {
        gll->modeindicator = "";
    }
    else
    {
        gll->modeindicator = msgs[7].left(1);
    }
    m_lastResult = gll;
    emit GLLFinished(gll);
}

void MsgParser::parseRMC(const QByteArray &msg)
{
    // 在《IEC 61162-1-2016（船舶通导设备输出输入数据格式）.pdf》中有navigational status字段，总共13个逗号
    // 但是在《IEC 61162.pdf》中没有navigational status，共12个逗号
    // 青岛测试拿回的数据中该报文也是没有这个字段
    //$BDRMC,013341.00,A,3000.35268,N,12203.27553,E,0.04,,150324,,,A,V*27
    const QByteArrayList msgs = msg.split(',');
    int n = msgs.count();
    if (n != 14 && n != 13)
        return;
    RMC *rmc = new RMC;
    rmc->type = getSatelliteType(msgs[0]);
    rmc->utc = CommonUtil::getUtc(msgs[9] + msgs[1], 2);
    rmc->status = msgs[2];
    rmc->lat = LonLatUtil::getLat(msgs.at(3), msgs.at(4));
    rmc->lon = LonLatUtil::getLon(msgs.at(5), msgs.at(6));
    rmc->speed = msgs[7].toDouble();
    rmc->course = msgs[8].toDouble();
    rmc->declination = msgs[10].toDouble();
    rmc->declinationdirection = msgs[11];

    rmc->modeindicator = msgs[12];
    m_lastResult = rmc;
    emit RMCFinished(rmc);
}

void MsgParser::parseVTG(const QByteArray &msg)
{
    // Example:  $GPVTG,268.6,T,275.8,M,0.0,N,0.0,K,A*21
    const QByteArrayList msgs = msg.split(',');
    if (msgs.count() != 10)
        return;
    VTG *vtg = new VTG;
    vtg->type = getSatelliteType(msgs[0]);
    vtg->course = msgs[1].toDouble();
    vtg->courseindicator = msgs[2];
    vtg->coursemagnetic = msgs[3].toDouble();
    vtg->coursemagneticindicator = msgs[4];
    vtg->speed = msgs[5].toDouble();
    vtg->speedunit = msgs[6];
    vtg->speedkm = msgs[7].toDouble();
    vtg->speedkmunit = msgs[8];

    if (msgs[9].left(1) == "*")
    {
        vtg->modeindicator = "";
    }
    else
    {
        vtg->modeindicator = msgs[9].left(1);
    }
    emit VTGFinished(vtg);
}

void MsgParser::parseRMB(const QByteArray &msg)
{
    // Example:  $GPRMB,A,9.99,R,0000,0054,3400.0000,N,12241.8880,E,172.3,135.0,0.0,A,A*51

    const QByteArrayList msgs = msg.split(',');
    if (msgs.count() != 15)
        return;
    RMB *rmb = new RMB;
    rmb->type = getSatelliteType(msgs[0]);
    rmb->status = msgs[1];
    rmb->crosstrack = msgs[2].toDouble();
    rmb->steeldirection = msgs[3];
    rmb->originid = msgs[4].toInt();
    rmb->destinationid = msgs[5].toInt();
    rmb->lat = LonLatUtil::getLonlat(msgs[6], 0);
    rmb->latdirection = msgs[7];
    rmb->lon = LonLatUtil::getLonlat(msgs[8], 1);
    rmb->londirection = msgs[9];
    rmb->distance = msgs[10].toDouble();
    rmb->bearing = msgs[11].toDouble();
    rmb->speed = msgs[12].toDouble();
    rmb->arrivalstatus = msgs[13];

    if (msgs[14].left(1) != "*")
    {
        rmb->modeindicator = "";
    }
    else
    {
        rmb->modeindicator = msgs[14].left(1);
    }
    emit RMBFinished(rmb);
}
void MsgParser::parseGNS(const QByteArray &msg)
{
    //    $GPGNS,122310.2,3722.425671,N,12258.856215,W,A,14,0.9,1005.543,6.5,5.2,23,S*hh
    const QByteArrayList msgs = msg.split(',');
    if (msgs.count() != 15)
        return;
    GNS *gns = new GNS;
    gns->type = getSatelliteType(msgs[0]);
    gns->utc = CommonUtil::getUtc(msgs[1], 0);

    gns->lat = LonLatUtil::getLonlat(msgs[2], 0);
    gns->latdirection = msgs[3];
    gns->lon = LonLatUtil::getLonlat(msgs[4], 1);
    gns->londirection = msgs[5];
    // gns->modeindicator    = msgs[6];

    gns->satellitecount = msgs[7].toInt();
    gns->hdop = msgs[8].toDouble();
    gns->altitude = msgs[9].toDouble();
    gns->geosep = msgs[10].toDouble();
    gns->difference = msgs[11].toDouble();
    gns->differenceid = msgs[12].toDouble();

    if (msgs[13].left(1) != "*")
    {
        gns->status = "";
    }
    else
    {
        gns->status = msgs[13].left(1);
    }
    emit GNSFinished(gns);
}

void MsgParser::parseTCI(const QByteArray &msg)
{
    // $BDTCI,1859818,1859818,2,020305,2,0,6F6E*43\r\n
    // 发信方ID,收信方ID,频点,时间hhmmss(UTC),编码类别(1-汉字,2-代码，3-混编，4-压缩汉字，5-压缩代码),数据标识(0-即时，1-邮箱),通信数据

    const QByteArrayList msgs = msg.split(',');
    if (msgs.size() != 8)
        return;
    TCI *tci = new TCI;
    tci->sendId = msgs.at(1).toULongLong();
    tci->receiveId = msgs.at(2).toULongLong();
    tci->lf = msgs.at(3).toInt();
    tci->time = QTime::fromString(msgs.at(4), "hhmmss").msecsSinceStartOfDay();
    tci->codeType = msgs.at(5).toInt();
    tci->dataId = msgs.at(6).toInt();
    QByteArray msgbody = msgs.at(7).chopped(3);
    if (tci->codeType == 1)
    {
        tci->msg = QString::fromLocal8Bit(msgbody);
    }
    else // if(msgInfo.codeType>=2)      // 实际接收中发现以混合方式和代码方式传过来的，到了接收时都是2
    {
        QByteArray s = msgbody;
        QByteArray rs;
        int n = msgbody.length();
        int si = (tci->codeType != 2 || msgbody.left(2) == "A4") ? 2 : 0;
        for (int i = si; i < n - 1; i += 2)
        {
            int a1 = XCharToNum(s.at(i)) * 16 + XCharToNum(s.at(i + 1));
            rs.push_back(char(a1));
        }
        tci->msg = QString::fromLocal8Bit(rs);
    }

    emit TCIFinished(tci);
}

int MsgParser::XCharToNum(char xch)
{
    int p0 = int('0');
    int pA = int('A');
    int px = int(xch);
    if (px >= pA)
        return (px - pA + 10);
    else
        return (px - p0);
}

void MsgParser::detectDevices()
{
    // for (int i = DeviceType::Ais; i < DeviceType::Other; i++)
    {
        int i = DeviceType::Ais;
        // if (MyLogger::developDebug)
        // MyLogger::developInfo(QString("detectDevice--currentTime:%1  lastUpdateTime:%2  elapsedTime:%3").arg(GTime::getUtcTime_s()).arg(m_deviceUpdateTime[i]).arg(GTime::getUtcTime_s() - m_deviceUpdateTime[i]).toStdString());
        if (m_deviceUpdateTime[i] == 0)
        {
            if (QDateTime::currentDateTime().toSecsSinceEpoch() - m_AISLastTime > 180)
            {
                if (!m_lostedDevices.contains(i))
                {
                    m_lostedDevices.append(i);
                    emit deviceLost(i);
                }
            }
        }
        else
        {
            if (GTime::getUtcTime_s() - m_deviceUpdateTime[i] > 180) // 三分钟没有收到数据，认为设备掉线 30秒用于测试
            {
                if (!m_lostedDevices.contains(i))
                {
                    m_lostedDevices.append(i);
                    emit deviceLost(i);
                }
            }
            else // 三分钟内收到数据
            {
                if (m_lostedDevices.contains(i))
                {
                    m_lostedDevices.removeOne(i);
                    emit deviceRecovered(i);
                }
            }
        }
    }
}

void *MsgParser::getLastResult()
{
    return m_lastResult;
}